/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.jxtafileshare;

import net.jxta.document.*;

import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Enumeration;
import java.util.logging.Logger;
import net.jxta.id.ID;
import net.jxta.id.IDFactory;

/**
 * Creates an advertisement describing a system
 */
public class FileAdvertisement extends Advertisement
                implements Comparable, Cloneable, Serializable {
    private String name;
    private String type;
    private ID id = null;

    private final static Logger LOG =
            Logger.getLogger(FileAdvertisement.class.getName());
    private final static String nameTag = "Name";
    private final static String typeTag = "Type";
    private final static String idTag = "ID";

    /**
     * Indexable fields. Advertisements must define the indexables
     * in order to properly index and retrieve these advertisements locally
     * and on the network
     */
    private final static String[] fields = {nameTag, typeTag};

    /**
     * Default constructor
     */

    public FileAdvertisement() {
    }

    /**
     * Construct from a StructuredDocument
     */
    public FileAdvertisement(Element root) {
        TextElement doc = (TextElement)root;

        if(!getAdvertisementType().equals(doc.getName())) {
            throw new IllegalArgumentException("Could not construct: " +
                    getClass().getName() + "from doc conaining a " +
                    doc.getName());
        }
        initialize(doc);
    }

    /**
     * Construct a doc from InputStream
     */
    public FileAdvertisement(InputStream stream) throws IOException {
        StructuredTextDocument doc = (StructuredTextDocument)
                StructuredDocumentFactory.
                newStructuredDocument(MimeMediaType.XMLUTF8, stream);
        initialize(doc);
    }

    /**
     * Set the file name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * Set the file type
     */
    public void setType(String type) {
        this.type = type;
    }

    public void setID(ID id) {
        this.id = id;
    }

    @Override
    public Document getDocument(MimeMediaType asMimeType) {
        StructuredDocument adv =
                StructuredDocumentFactory.newStructuredDocument(asMimeType,
                    getAdvertisementType());
        if(adv instanceof Attributable) {
            ((Attributable)adv).addAttribute("xmlns:jxta", "http://jxta.org");
        }
        Element e;
        e = adv.createElement(idTag, getID().toString());
        adv.appendChild(e);
        e = adv.createElement(nameTag, getName().trim());
        adv.appendChild(e);
        e = adv.createElement(typeTag, getType().trim());
        adv.appendChild(e);
        return adv;
    }

    /**
     * Get the device ID
     */
    @Override
    public ID getID() {
        return(id == null ? null : id);
    }

    public String getType() {
        return type;
    }

    @Override
    public String[] getIndexFields() {
        return fields;
    }

    public int compareTo(Object other) {
        return getID().toString().compareTo(other.toString());
    }

    @Override
    public boolean equals(Object obj) {
        if(this == obj) {
            return true;
        }
        if(obj instanceof FileAdvertisement) {
            FileAdvertisement adv = (FileAdvertisement)obj;
            return getID().equals(adv.getID());
        }
        return false;
    }

    /**
     * Get the advertisement type
     */
    public static String getAdvertisementType() {
        return "jxta:Advertisement";
    }

    /**
     * Get the Advertisement document text
     */
    public String getName() {
        return name;
    }
    /**
     * Processes an individual element from the document.
     */
    protected boolean handleElement(TextElement elem) {
        if(elem.getName().equals(idTag)) {
            try {
                URI id = new URI(elem.getTextValue());
                setID(IDFactory.fromURI(id));
            } catch(URISyntaxException badID) {
                throw new IllegalArgumentException("unknown ID format in" +
                        "advertisement: " + elem.getTextValue());
            } catch(ClassCastException badID) {
                throw new IllegalArgumentException("Id is not a known id type: " +
                        elem.getTextValue());
            }
            return true;
        }
        if(elem.getName().equals(nameTag)) {
            setName(elem.getTextValue());
            return true;
        }
        // element was not handled
        return false;
    }
    protected void initialize(Element root) {
        if(!TextElement.class.isInstance(root)) {
            throw new IllegalArgumentException(getClass().getName() +
                    " only supports TextElement");
        }
        TextElement doc = (TextElement)root;
        if(!doc.getName().equals(getAdvertisementType())) {
            throw new IllegalArgumentException("Could not construct: " +
                    getClass().getName() + "from doc containing a " +
                    doc.getName());
        }
        Enumeration elements = doc.getChildren();
        while(elements.hasMoreElements()) {
            TextElement elem = (TextElement)elements.nextElement();
            if(!handleElement(elem)) {
                LOG.warning("Unhandled element \'" + elem.getName() + "\' in " +
                        doc.getName());
            }
        }
    }

    public static class Instantiator implements AdvertisementFactory.Instantiator {
        /**
         * Returns the identifying type of this advertisement
         */
        public String getAdvertisementType() {
            return FileAdvertisement.getAdvertisementType();
        }

        /**
         * Constructs an instnce of an advertisement matching the type
         * specified by the advertisementType parameter
         */
        public Advertisement newInstance() {
            return new FileAdvertisement();
        }

        /**
         * Construct a new advertisement matching the type
         * specified by the advertisementType parameter
         */
        public Advertisement newInstance(net.jxta.document.Element root) {
            return new FileAdvertisement(root);
        }
    }
}
